package task

import (
	"github.com/jakecoffman/cron"
	"strconv"
	"strings"
	"app/models"
	"until/logger"
	"github.com/kataras/iris/context"
	"app/service"
	"until/urldata"
	"app/controller/base"
	"until/db"
	"tools/normal"
	"until/validate"
)

type TaskForm struct {
	Id               int				`form:"id"`
	Level            models.TaskLevel 		`form:"level" validate:"required,eq=1|eq=2"`
	DependencyStatus models.TaskDependencyStatus	`form:"dependency_status"`
	DependencyTaskId string				`form:"dependency_taskid"`
	Name             string 			`form:"name" validate:"required,max=32"`
	Spec             string				`form:"spec"`
	Protocol         models.TaskProtocol 		`form:"protocol" validate:"required,eq=1|eq=2"`
	Command          string              		`form:"command" validate:"required,max=256"`
	Timeout          int                 		`form:"timeout" validate:"gte=0,lt=86400"`
	Multi            int8                		`form:"multi" validate:"eq=1|eq=2"`
	RetryTimes       int8				`form:"retry_times"`
	RetryInterval    int16				`form:"retry_interval"`
	HostId           string				`form:"host_id"`
	Tag              string				`form:"tag"`
	Remark           string				`form:"remark"`
	NotifyStatus     int8 				`form:"notify_status" validate:"eq=0|eq=1"`
	NotifyType       int8 				`form:"notify_type" validate:"eq=1|eq=2|eq=3"`
	NotifyReceiverId string				`form:"notify_receiver_id"`
}

func List(ctx context.Context){
	taskModel := new(models.Task)
	queryParams := parseQueryParams(ctx)
	hosts, err := taskModel.List(queryParams)
	if err != nil {
		logger.Error(err)
		ctx.JSON(urldata.RetFail("错误"))
		return

	}
	ctx.JSON(urldata.RetSuccess(hosts))
}
// 保存任务
func Store(ctx context.Context){
	form:=TaskForm{}
	err:=ctx.ReadForm(&form)
	if err!=nil {
		ctx.JSON(urldata.RetFail("参数错误:"+err.Error()))
		return
	}
	err=validate.Validate.Struct(form)
	if err!=nil {
		ctx.JSON(urldata.RetFail("参数校验失败:"+err.Error()))
		return
	}
	taskModel := models.Task{}
	var id int = form.Id
	nameExists, err := taskModel.NameExist(form.Name, form.Id)
	if err != nil {
		ctx.JSON(urldata.RetFail("查询失败"))
		return
	}
	if nameExists {
		ctx.JSON(urldata.RetFail("任务存在"))
		return
	}

	if form.Protocol == models.TaskRPC && form.HostId == "" {
		ctx.JSON(urldata.RetFail("请选择主机名"))
		return
	}

	taskModel.Name = form.Name
	taskModel.Protocol = form.Protocol
	taskModel.Command = form.Command
	taskModel.Timeout = form.Timeout
	taskModel.Tag = form.Tag
	taskModel.Remark = form.Remark
	taskModel.Multi = form.Multi
	taskModel.RetryTimes = form.RetryTimes
	taskModel.RetryInterval = form.RetryInterval
	if taskModel.Multi != 1 {
		taskModel.Multi = 0
	}
	taskModel.NotifyStatus = form.NotifyStatus
	taskModel.NotifyType = form.NotifyType
	taskModel.NotifyReceiverId = form.NotifyReceiverId
	taskModel.Spec = form.Spec
	taskModel.Level = form.Level
	taskModel.DependencyStatus = form.DependencyStatus
	taskModel.DependencyTaskId = strings.TrimSpace(form.DependencyTaskId)
	if taskModel.NotifyStatus > 0 && taskModel.NotifyReceiverId == "" {
		ctx.JSON(urldata.RetFail("至少选择一个通知接收者"))
		return
	}
	if taskModel.Protocol == models.TaskHTTP {
		command := strings.ToLower(taskModel.Command)
		if !strings.HasPrefix(command, "http://") && !strings.HasPrefix(command, "https://") {
			ctx.JSON(urldata.RetFail("请输入正确的URL地址"))
			return
		}
		if taskModel.Timeout > 300 {
			ctx.JSON(urldata.RetFail("HTTP任务超时时间不能超过300秒"))
			return
		}
	}

	if taskModel.RetryTimes > 10 || taskModel.RetryTimes < 0 {
		ctx.JSON(urldata.RetFail("任务重试次数取值0-10"))
		return
	}

	if taskModel.RetryInterval > 3600 || taskModel.RetryInterval < 0 {
		ctx.JSON(urldata.RetFail("任务重试间隔时间取值0-3600"))
		return
	}

	if taskModel.DependencyStatus != models.TaskDependencyStatusStrong &&
		taskModel.DependencyStatus != models.TaskDependencyStatusWeak {
		ctx.JSON(urldata.RetFail("请选择依赖关系"))
		return
	}

	if taskModel.Level == models.TaskLevelParent {
		_,err:=cron.Parse(form.Spec)
		if err != nil {
			ctx.JSON(urldata.RetFail("crontab表达式解析失败"))
			return
		}
	} else {
		taskModel.DependencyTaskId = ""
		taskModel.Spec = ""
	}

	if id > 0 && taskModel.DependencyTaskId != "" {
		dependencyTaskIds := strings.Split(taskModel.DependencyTaskId, ",")
		if normal.InStringSlice(dependencyTaskIds, strconv.Itoa(id)) {
			ctx.JSON(urldata.RetFail("不允许设置当前任务为子任务"))
			return
		}
	}

	if id == 0 {
		// 任务添加后开始调度执行
		taskModel.Status = db.Running
		id, err = taskModel.Create()
	} else {
		_, err = taskModel.UpdateBean(id)
	}

	if err != nil {
		ctx.JSON(urldata.RetFail("保存失败"))
		return
	}

	taskHostModel := new(models.TaskHost)
	if form.Protocol == models.TaskRPC {
		hostIdStrList := strings.Split(form.HostId, ",")
		hostIds := make([]int, len(hostIdStrList))
		for i, hostIdStr := range hostIdStrList {
			hostIds[i], _ = strconv.Atoi(hostIdStr)
		}
		taskHostModel.Add(id, hostIds)
	} else {
		taskHostModel.Remove(id)
	}

	status, _ := taskModel.GetStatus(id)
	if status == db.Enabled && taskModel.Level == models.TaskLevelParent {
		task, err := taskModel.Detail(id)
		if err != nil {
			logger.Error(err)
			ctx.JSON(urldata.RetFail("添加到任务失败"))
			return
		}
		taskService := service.Task{}
		taskService.Add(task)
	}
	ctx.JSON(urldata.RetSuccess("保存成功"))
}

// 删除任务
func Del(ctx context.Context) {
	id,err:=ctx.Params().GetInt("id")
	if err!=nil||id<=0 {
		ctx.JSON(urldata.RetFail("参数错误"))
		return
	}
	taskModel := new(models.Task)
	did, err:= taskModel.Delete(id)
	if err != nil||did<=0 {
		ctx.JSON(urldata.RetFail("删除失败"))
		return
	}
	taskHostModel := new(models.TaskHost)
	taskHostModel.Remove(id)
	service.Cron.RemoveJob(strconv.Itoa(id))
	ctx.JSON(urldata.RetSuccess("删除成功"))
}

// 任务状态
func Status(ctx context.Context){
	status,err:=ctx.Params().GetInt("status")
	id,err:=ctx.Params().GetInt("id")
	if err!=nil||(status!=0||status!=1)||id<=0 {
		ctx.JSON(urldata.RetFail("参数错误"))
		return
	}
	taskModel := new(models.Task)
	_, err= taskModel.Update(id, models.CommonMap{
		"Status": status,
	})
	if err!=nil {
		ctx.JSON(urldata.RetFail("更新状态失败"))
		return
	}
	switch status {
	case 0:
		service.Cron.RemoveJob(strconv.Itoa(id))
		break
	case 1:
		task, err := taskModel.Detail(id)
		if err != nil {
			logger.Error(err)
			ctx.JSON(urldata.RetFail("获取任务信息失败"))
			return
		}
		taskService := service.Task{}
		taskService.Add(task)
		break
	default:
		ctx.JSON(urldata.RetFail("修改状态失败"))
		return
	}
	ctx.JSON(urldata.RetSuccess("修改成功"))
}

// 手动运行任务
func Run(ctx context.Context){
	id,err:=ctx.Params().GetInt("id")
	if err!=nil||id<=0 {
		ctx.JSON(urldata.RetFail("参数错误"))
		return
	}
	taskModel := new(models.Task)
	task, err := taskModel.Detail(id)
	if err != nil || task.Id <= 0 {
		ctx.JSON(urldata.RetFail("获取任务详情失败"))
		return
	}

	task.Spec = "手动运行"
	serviceTask := new(service.Task)
	serviceTask.Run(task)
	ctx.JSON(urldata.RetSuccess("任务已开始运行, 请到任务日志中查看结果"))
}

// 解析查询参数
func parseQueryParams(ctx context.Context) models.CommonMap {
	var params models.CommonMap = models.CommonMap{}
	params["Id"],_ =ctx.PostValueInt("id")
	params["HostId"],_ = ctx.PostValueInt("host_id")
	params["Name"]= ctx.PostValueTrim("name")
	params["Protocol"],_ = ctx.PostValueInt("protocol")
	params["Tag"]= ctx.PostValueTrim("tag")
	status ,_:= ctx.PostValueInt("status")
	if status >= 0 {
		status -= 1
	}
	params["Status"] = status
	base.ParsePageAndPageSize(ctx, params)
	return params
}
